//
// Created by Sivin on 2024/5/10.
//

#include <iostream>
#include <sstream>
#include <iomanip>
#include <sys/stat.h>
#include <csignal>
#include "MediaOutput.h"
#include "RtspInput.h"

static bool isExit = false;

static int checkOutDir(const std::string &outDir) {
  struct stat info{};
  if (stat(outDir.c_str(), &info) != 0) {
    if (errno == ENOENT) {
      std::cerr << "OutDir does not exist. Please check and try again" << std::endl;
      return -1;
    } else {
      perror("OutDir file stat failed");
      return -1;
    }
  } else if (!(info.st_mode & S_IFDIR)) {
    // 路径存在，但不是目录
    std::cerr << "OutDir exists but is not a directory." << std::endl;
    return -1;
  }
  return 0;
}

void handle_sigint(int sig) {
  isExit = true;
  std::cout << "Recoder prepare exit..." << std::endl;
}

class CMDParams {
public:
  std::string url;
  std::string outDir;
  long segmentTime{3600};
};


static std::string help =
    "global options:\n"
    " -i      :rtsp url\n"
    " -o      :avi save dir\n"
    " -seg    :The number of seconds a media file recorded, default is 3600\n";

static CMDParams parseCmdArgs(int argc, char *argv[]) {
  CMDParams params;
  for (int i = 1; i < argc; ++i) {
    std::string arg = argv[i];
    if (i + 1 >= argc) {
      break;
    }
    if (arg == "--help" || arg == "-h") {
      std::cout << help;
      exit(0);
    } else if (arg == "-i") {
      params.url = argv[i + 1];
      i++;
    } else if (arg == "-o") {
      params.outDir = argv[i + 1];
      i++;
    } else if (arg == "-seg") {
      char *endPtr = nullptr;
      params.segmentTime = std::strtol(argv[i + 1], &endPtr, 10);
      if (*endPtr != '\0') {
        params.segmentTime = 3600;
        printf("input an invalid segmentTime.\n");
      }
    }
  }
  return params;
}


int main(int argc, char *argv[]) {
  CMDParams params = parseCmdArgs(argc, argv);

  if (params.url.empty()) {
    printf("Please input a rtsp url.\n");
    return 0;
  }

  if (params.outDir.empty()) {
    printf("Please input a outDir.\n");
    return 0;
  }

  printf("parse args result:\n"
         "  url = %s\n"
         "  saveDir = %s\n"
         "  segmentTime = %ld\n",
         params.url.c_str(), params.outDir.c_str(), params.segmentTime);

  if (checkOutDir(params.outDir) != 0) {
    return 0;
  }

  //设置信号处理函数
  signal(SIGINT, handle_sigint);

  auto *rtspInput = new RtspInput(params.url);
  if (rtspInput->Open() != 0) {
    std::cout << "open url:" << params.url << " failed." << std::endl;
    return -1;
  }

  MediaOutput *mediaOutput = nullptr;

  bool needSlice = false;
  bool canRecord = false;

  time_t start = time(nullptr);
  MediaPacket packet;
  while (!isExit && rtspInput->ReadPacket(packet) == 0) {
    if (!packet.isVideo) {
      packet.release();
      continue;
    }
    if (packet.isKeyFrame) {
      if (needSlice) {
        if (mediaOutput != nullptr) {
          mediaOutput->Close();
          delete mediaOutput;
          mediaOutput = nullptr;
        }
        start = time(nullptr);
        needSlice = false;
      }
      canRecord = true;
    }

    if (!canRecord) {
      packet.release();
      continue;
    }

    if (mediaOutput == nullptr) {
      start = time(nullptr);
      struct tm now_tm{};
      localtime_r(&start, &now_tm);
      std::stringstream ss;
      ss << std::put_time(&now_tm, "%Y%m%d%H%M%S");
      mediaOutput = new MediaOutput(params.outDir + "/" + ss.str() + ".avi");
      mediaOutput->Configure(rtspInput->GetCodecPar());
      mediaOutput->Open();
    }
    mediaOutput->WritePacket(packet, true, rtspInput->GetTimeBase());
    if (time(nullptr) - start > params.segmentTime) {
      needSlice = true;
    }
    packet.release();
  }

  if (mediaOutput != nullptr) {
    mediaOutput->Close();
    delete mediaOutput;
  }

  delete rtspInput;
  std::cout << "Recoder finished..." << std::endl;
  return 0;
}

